package org.daochong.fastdev.controllor;

import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.daochong.fastdev.Context;
import org.daochong.fastdev.DefaultJdbcOperations;
import org.daochong.fastdev.DefaultJpaOperations;
import org.daochong.fastdev.IClassMappingFactory;
import org.daochong.fastdev.IExecutor;
import org.daochong.fastdev.JdbcOperations;
import org.daochong.fastdev.JpaOperations;
import org.daochong.lang.BeanUtil;
import org.daochong.lang.JdbcTemplateProvider;
import org.daochong.lang.JsonAccessException;
import org.daochong.lang.Page;
import org.daochong.spring.controllor.BaseControllor;
import org.daochong.web.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.support.WebApplicationContextUtils;

@Controller
@RequestMapping("/f")
public class FastDevControllor extends BaseControllor {

	public static String DEFAULT_JPA_ID = "id";

	@Autowired
	@Qualifier("fastDevExecutor")
	private IExecutor executor;

	@Autowired
	@Qualifier("fastDevClassMappingFactory")
	private IClassMappingFactory classMappingFactory;

	@Autowired
	@Qualifier("fastDevJdbcTemplateProvider")
	private JdbcTemplateProvider jdbcTemplateProvider;

	public JdbcOperations getJdbcOperations(HttpServletRequest request) {
		DefaultJdbcOperations jo = new DefaultJdbcOperations();
		if (request.getParameter("configId") == null) {
			jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte());
		} else {
			if (request.getParameter("groupId") == null) {
				jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte(request.getParameter("configId")));
			} else {
				jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte(request.getParameter("configId"),
						request.getParameter("groupId")));
			}
		}
		return jo;
	}

	public JpaOperations getJpaOperations(HttpServletRequest request) {
		DefaultJpaOperations jo = new DefaultJpaOperations();
		if (request.getParameter("configId") == null) {
			jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte());
		} else {
			if (request.getParameter("groupId") == null) {
				jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte(request.getParameter("configId")));
			} else {
				jo.setJdbc(jdbcTemplateProvider.requestJdbcTempalte(request.getParameter("configId"),
						request.getParameter("groupId")));
			}
		}
		return jo;
	}

	@RequestMapping(value = "/form/{action:.*}")
	public String form(@PathVariable String action, HttpServletRequest request, HttpServletResponse response) {
		Context context = executor.exec("form.", action, WebUtils.getParameterMapObject(request),
				toAttributes(request, response), request);
		Map<String, Object> re = context.getReturnObjects();
		for (String key : re.keySet()) {
			request.setAttribute(key, re.get(key));
		}
		if (context.isSuccess()) {
			return context.getView();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new RuntimeException("Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new RuntimeException("Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/form/{action:.*}/{sub:.*}")
	public String form(@PathVariable String action, @PathVariable String sub, HttpServletRequest request,
			HttpServletResponse response) {
		Context context = executor.exec("form.", action + "." + sub, WebUtils.getParameterMapObject(request),
				toAttributes(request, response), request);
		Map<String, Object> re = context.getReturnObjects();
		for (String key : re.keySet()) {
			request.setAttribute(key, re.get(key));
		}
		if (context.isSuccess()) {
			return context.getView();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new RuntimeException("Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new RuntimeException("Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/form/{action:.*}/{sub:.*}/{subChild:.*}")
	public String form(@PathVariable String action, @PathVariable String sub, @PathVariable String subChild,
			HttpServletRequest request, HttpServletResponse response) {
		Context context = executor.exec("form.", action + "." + sub + "." + subChild,
				WebUtils.getParameterMapObject(request), toAttributes(request, response), request);
		Map<String, Object> re = context.getReturnObjects();
		for (String key : re.keySet()) {
			request.setAttribute(key, re.get(key));
		}
		if (context.isSuccess()) {
			return context.getView();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new RuntimeException("Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new RuntimeException("Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/api/{action:.*}")
	@ResponseBody
	public Object api(@PathVariable String action, HttpServletRequest request, HttpServletResponse response) {
		Context context = executor.exec("api.", action, WebUtils.getParameterMapObject(request),
				toAttributes(request, response), request);
		if (context.isSuccess()) {
			return context.getReturnObjects();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new JsonAccessException(10000, "Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new JsonAccessException(10000, "Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/api/{action:.*}/{sub:.*}")
	@ResponseBody
	public Object api(@PathVariable String action, @PathVariable String sub, HttpServletRequest request,
			HttpServletResponse response) {
		Context context = executor.exec("api.", action + "." + sub, WebUtils.getParameterMapObject(request),
				toAttributes(request, response), request);
		if (context.isSuccess()) {
			return context.getReturnObjects();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new JsonAccessException(10000, "Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new JsonAccessException(10000, "Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/api/{action:.*}/{sub:.*}/{subChild:.*}")
	@ResponseBody
	public Object api(@PathVariable String action, @PathVariable String sub, @PathVariable String subChild,
			HttpServletRequest request, HttpServletResponse response) {
		Context context = executor.exec("api.", action + "." + sub + "." + subChild,
				WebUtils.getParameterMapObject(request), toAttributes(request, response), request);
		if (context.isSuccess()) {
			return context.getReturnObjects();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new JsonAccessException(10000, "Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new JsonAccessException(10000, "Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/r/{entity:.*}")
	@ResponseBody
	public Object execNoId(@PathVariable String entity, HttpServletRequest request, HttpServletResponse response) {
		Context context = executor.execJpa(entity, request.getMethod(), WebUtils.getParameterMapObject(request),
				toAttributes(request, response), request);
		if (context.isSuccess()) {
			return context.getReturnObjects();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new JsonAccessException(10000, "Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new JsonAccessException(10000, "Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/r/{entity:.*}/{id:.*}")
	@ResponseBody
	public Object exec(@PathVariable String entity, @PathVariable String id, HttpServletRequest request,
			HttpServletResponse response) {
		Map<String, Object> params = WebUtils.getParameterMapObject(request);
		params.put("id", id);
		Context context = executor.execJpa(entity, request.getMethod(), params, toAttributes(request, response),
				request);
		if (context.isSuccess()) {
			return context.getReturnObjects();
		} else {
			if (context.getExceptions() != null && context.getExceptions().size() > 0) {
				throw new JsonAccessException(10000, "Action Execute Exception", context.getExceptions().get(0));
			} else {
				throw new JsonAccessException(10000, "Action Execute Exception");
			}
		}
	}

	@RequestMapping(value = "/value/{sqlId:.*}")
	@ResponseBody
	public Object value(@PathVariable String sqlId, HttpServletRequest request) {
		try {
			return getJdbcOperations(request).value(sqlId, WebUtils.getParameterMapObject(request));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/get/{sqlId:.*}")
	@ResponseBody
	public Object get(@PathVariable String sqlId, HttpServletRequest request) {
		try {
			return getJdbcOperations(request).get(sqlId, WebUtils.getParameterMapObject(request));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/list/{sqlId:.*}")
	@ResponseBody
	public Object list(@PathVariable String sqlId, HttpServletRequest request) {
		try {
			return getJdbcOperations(request).list(sqlId, WebUtils.getParameterMapObject(request));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/page/{sqlId:.*}")
	@ResponseBody
	public Object page(@PathVariable String sqlId, HttpServletRequest request) {
		try {
			Map<String, Object> params = WebUtils.getParameterMapObject(request);
			return getJdbcOperations(request).page(BeanUtil.pushBean(params, Page.class), sqlId, params);
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/exec/{sqlId:.*}")
	@ResponseBody
	public Object exec(@PathVariable String sqlId, HttpServletRequest request) {
		try {
			return getJdbcOperations(request).exec(sqlId, WebUtils.getParameterMapObject(request));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/exists/{entity:.*}")
	@ResponseBody
	public Object exists(@PathVariable String entity, HttpServletRequest request) {
		try {
			Object o = this.classMappingFactory.getEntity(entity, WebUtils.getParameterMapObject(request));
			return this.getJpaOperations(request).exists(o);
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/save/{entity:.*}")
	@ResponseBody
	public Object save(@PathVariable String entity, HttpServletRequest request) {
		try {
			Map<String, Object> params = WebUtils.getParameterMapObject(request);
			Object o = this.classMappingFactory.getEntity(entity, params);
			Map<String, Object> extData = BeanUtil.getExtDatas(o, params);
			return this.getJpaOperations(request).save(o, extData);
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/listObject/{entity:.*}")
	@ResponseBody
	public Object listEntity(@PathVariable String entity, HttpServletRequest request) {
		try {
			return this.getJpaOperations(request).list(this.classMappingFactory.getEntity(entity));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/list/{entity:.*}/{sqlId:.*}")
	@ResponseBody
	public Object listEntity(@PathVariable String entity, @PathVariable String sqlId, HttpServletRequest request) {
		try {
			return this.getJpaOperations(request).listBySql(sqlId, this.classMappingFactory.getEntity(entity),
					WebUtils.getParameterMapObject(request));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/pageObject/{entity:.*}")
	@ResponseBody
	public Object pageEntity(@PathVariable String entity, HttpServletRequest request) {
		try {
			Map<String, Object> params = WebUtils.getParameterMapObject(request);
			return this.getJpaOperations(request).page(BeanUtil.pushBean(params, Page.class),
					this.classMappingFactory.getEntity(entity));
		} catch (Throwable e) {
			throw process(e);
		}
	}

	@RequestMapping(value = "/page/{entity:.*}/{sqlId:.*}")
	@ResponseBody
	public Object pageEntity(@PathVariable String entity, @PathVariable String sqlId, HttpServletRequest request) {
		try {
			Map<String, Object> params = WebUtils.getParameterMapObject(request);
			return this.getJpaOperations(request).pageBySql(BeanUtil.pushBean(params, Page.class), sqlId,
					this.classMappingFactory.getEntity(entity), params);
		} catch (Throwable e) {
			throw process(e);
		}
	}

	private Map<String, Object> toAttributes(HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> attrs = new LinkedHashMap<String, Object>();
		attrs.put("clientIp", WebUtils.getRealIp(request));
		attrs.put("serverIp", request.getServerName());
		attrs.put("request", request);
		attrs.put("session", request.getSession(true));
		attrs.put("response", response);
		attrs.put("cookies", WebUtils.getCookiesMap(request));
		attrs.put("contentPath", request.getContextPath());
		attrs.put("requestURI", request.getRequestURI());
		attrs.put("requestMethod", request.getMethod());
		Enumeration<String> names = request.getAttributeNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			attrs.put(name, request.getAttribute(name));
		}
		try {
			attrs.put("applicationContext",
					WebApplicationContextUtils.getWebApplicationContext(request.getServletContext()));
		} catch (Throwable e) {
			
		}
		return attrs;
	}
}
